package com.example.smartpark.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.smartpark.dto.ReservationDTO;
import com.example.smartpark.dto.ReservationQueryDTO;
import com.example.smartpark.exception.BusinessException;
import com.example.smartpark.mapper.ReservationMapper;
import com.example.smartpark.mapper.ParkingSpaceMapper;
import com.example.smartpark.mapper.UserMapper;
import com.example.smartpark.mapper.VehicleMapper;
import com.example.smartpark.model.Reservation;
import com.example.smartpark.model.ParkingSpace;
import com.example.smartpark.model.User;
import com.example.smartpark.model.Vehicle;
import com.example.smartpark.service.ReservationService;
import com.example.smartpark.mapper.FeeStandardMapper;
import com.example.smartpark.model.FeeStandard;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * 预约服务实现类
 */
@Slf4j
@Service
public class ReservationServiceImpl extends ServiceImpl<ReservationMapper, Reservation> implements ReservationService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private VehicleMapper vehicleMapper;

    @Autowired
    private ParkingSpaceMapper parkingSpaceMapper;

    @Autowired
    private FeeStandardMapper feeStandardMapper;

    @Override
    public IPage<ReservationDTO> getReservationPage(ReservationQueryDTO queryDTO) {
        // 构建分页对象
        Page<Reservation> page = new Page<>(queryDTO.getPage(), queryDTO.getSize());

        // 构建查询条件
        LambdaQueryWrapper<Reservation> queryWrapper = new LambdaQueryWrapper<>();
        
        // 添加查询条件
        if (!Boolean.TRUE.equals(queryDTO.getIsAdmin()) && queryDTO.getUserId() != null) {
            queryWrapper.eq(Reservation::getUserId, queryDTO.getUserId());
        }
        
        if (queryDTO.getVehicleId() != null) {
            queryWrapper.eq(Reservation::getVehicleId, queryDTO.getVehicleId());
        }
        
        if (queryDTO.getParkingSpaceId() != null) {
            queryWrapper.eq(Reservation::getParkingSpaceId, queryDTO.getParkingSpaceId());
        }
        
        if (queryDTO.getStatus() != null) {
            queryWrapper.eq(Reservation::getStatus, queryDTO.getStatus());
        }
        
        if (queryDTO.getStartTimeBegin() != null) {
            queryWrapper.ge(Reservation::getStartTime, queryDTO.getStartTimeBegin());
        }
        
        if (queryDTO.getStartTimeEnd() != null) {
            queryWrapper.le(Reservation::getStartTime, queryDTO.getStartTimeEnd());
        }
        
        if (queryDTO.getCreatedAtBegin() != null) {
            queryWrapper.ge(Reservation::getCreatedAt, queryDTO.getCreatedAtBegin());
        }
        
        if (queryDTO.getCreatedAtEnd() != null) {
            queryWrapper.le(Reservation::getCreatedAt, queryDTO.getCreatedAtEnd());
        }
        
        // 添加排序条件（按创建时间降序）
        queryWrapper.orderByDesc(Reservation::getCreatedAt);
        
        // 执行分页查询
        IPage<Reservation> reservationPage = this.page(page, queryWrapper);
        
        // 转换为DTO
        IPage<ReservationDTO> dtoPage = reservationPage.convert(this::convertToDTO);
        
        return dtoPage;
    }

    @Override
    public ReservationDTO getReservationById(Long id) {
        // 查询预约
        Reservation reservation = this.getById(id);
        if (reservation == null) {
            throw new BusinessException("预约不存在");
        }
        
        // 转换为DTO
        return convertToDTO(reservation);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ReservationDTO createReservation(ReservationDTO reservationDTO) {
        // 验证车辆是否存在
        Vehicle vehicle = vehicleMapper.selectById(reservationDTO.getVehicleId());
        if (vehicle == null) {
            throw new BusinessException("车辆不存在");
        }
        
        // 验证车辆是否属于当前用户
        if (!Objects.equals(vehicle.getUserId(), reservationDTO.getUserId())) {
            throw new BusinessException("无权操作此车辆");
        }
        
        // 验证车位是否存在
        ParkingSpace parkingSpace = parkingSpaceMapper.selectById(reservationDTO.getParkingSpaceId());
        if (parkingSpace == null) {
            throw new BusinessException("车位不存在");
        }
        
        // 验证车位是否可预约（状态为空闲）
        if (parkingSpace.getStatus() != 0) {
            throw new BusinessException("车位不可预约");
        }
        
        // 验证预约时间是否合理
        Date now = new Date();
        if (reservationDTO.getStartTime().before(now)) {
            throw new BusinessException("预约开始时间不能早于当前时间");
        }
        
        if (reservationDTO.getEndTime().before(reservationDTO.getStartTime())) {
            throw new BusinessException("预约结束时间不能早于开始时间");
        }
        
        // 验证预约时间段是否已被占用
        LambdaQueryWrapper<Reservation> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Reservation::getParkingSpaceId, reservationDTO.getParkingSpaceId())
                .and(w -> w.eq(Reservation::getStatus, 0).or().eq(Reservation::getStatus, 1))
                .and(w -> 
                    // 开始时间在已有预约的时间范围内
                    w.between(Reservation::getStartTime, reservationDTO.getStartTime(), reservationDTO.getEndTime())
                    // 或结束时间在已有预约的时间范围内
                    .or().between(Reservation::getEndTime, reservationDTO.getStartTime(), reservationDTO.getEndTime())
                    // 或已有预约的时间范围包含新预约的时间范围
                    .or(ww -> ww.le(Reservation::getStartTime, reservationDTO.getStartTime())
                            .ge(Reservation::getEndTime, reservationDTO.getEndTime()))
                );
        
        long count = this.count(queryWrapper);
        if (count > 0) {
            throw new BusinessException("该时间段内车位已被预约");
        }
        
        // 创建预约
        Reservation reservation = new Reservation();
        BeanUtils.copyProperties(reservationDTO, reservation);
        
        // 设置初始状态为待审核
        reservation.setStatus(0);
        
        // 计算预约费用
        BigDecimal fee = calculateReservationFee(parkingSpace, reservationDTO.getStartTime(), reservationDTO.getEndTime());
        reservation.setFee(fee);
        
        // 设置未支付状态
        reservation.setIsPaid(0);
        
        // 保存预约
        this.save(reservation);
        
        // 更新车位状态为已预约
        parkingSpace.setStatus(2); // 2表示已预约
        parkingSpaceMapper.updateById(parkingSpace);
        
        // 返回DTO
        return convertToDTO(reservation);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ReservationDTO cancelReservation(Long id, String remark) {
        // 查询预约
        Reservation reservation = this.getById(id);
        if (reservation == null) {
            throw new BusinessException("预约不存在");
        }
        
        // 验证预约状态是否可取消（只有待审核和已确认的预约可以取消）
        if (reservation.getStatus() != 0 && reservation.getStatus() != 1) {
            throw new BusinessException("当前状态不可取消预约");
        }
        
        // 更新预约状态为已取消
        reservation.setStatus(3); // 3表示已取消
        reservation.setRemark(remark);
        reservation.setUpdatedAt(new Date());
        this.updateById(reservation);
        
        // 更新车位状态为空闲
        ParkingSpace parkingSpace = parkingSpaceMapper.selectById(reservation.getParkingSpaceId());
        if (parkingSpace != null) {
            parkingSpace.setStatus(0); // 0表示空闲
            parkingSpaceMapper.updateById(parkingSpace);
        }
        
        // 返回DTO
        return convertToDTO(reservation);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ReservationDTO confirmReservation(Long id) {
        // 查询预约
        Reservation reservation = this.getById(id);
        if (reservation == null) {
            throw new BusinessException("预约不存在");
        }
        
        // 验证预约状态是否可确认（只有待审核的预约可以确认）
        if (reservation.getStatus() != 0) {
            throw new BusinessException("当前状态不可确认预约");
        }
        
        // 更新预约状态为已确认
        reservation.setStatus(1); // 1表示已确认
        reservation.setUpdatedAt(new Date());
        this.updateById(reservation);
        
        // 返回DTO
        return convertToDTO(reservation);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ReservationDTO rejectReservation(Long id, String remark) {
        // 查询预约
        Reservation reservation = this.getById(id);
        if (reservation == null) {
            throw new BusinessException("预约不存在");
        }
        
        // 验证预约状态是否可拒绝（只有待审核的预约可以拒绝）
        if (reservation.getStatus() != 0) {
            throw new BusinessException("当前状态不可拒绝预约");
        }
        
        // 更新预约状态为已拒绝
        reservation.setStatus(4); // 4表示已拒绝
        reservation.setRemark(remark);
        reservation.setUpdatedAt(new Date());
        this.updateById(reservation);
        
        // 更新车位状态为空闲
        ParkingSpace parkingSpace = parkingSpaceMapper.selectById(reservation.getParkingSpaceId());
        if (parkingSpace != null) {
            parkingSpace.setStatus(0); // 0表示空闲
            parkingSpaceMapper.updateById(parkingSpace);
        }
        
        // 返回DTO
        return convertToDTO(reservation);
    }

    /**
     * 将实体转换为DTO
     *
     * @param reservation 预约实体
     * @return 预约DTO
     */
    private ReservationDTO convertToDTO(Reservation reservation) {
        if (reservation == null) {
            return null;
        }
        
        ReservationDTO dto = new ReservationDTO();
        BeanUtils.copyProperties(reservation, dto);
        
        // 设置状态描述
        dto.setStatusDesc(getStatusDesc(reservation.getStatus()));
        
        // 查询用户信息
        User user = userMapper.selectById(reservation.getUserId());
        if (user != null) {
            dto.setUsername(user.getUsername());
            dto.setRealName(user.getRealName());
        }
        
        // 查询车辆信息
        Vehicle vehicle = vehicleMapper.selectById(reservation.getVehicleId());
        if (vehicle != null) {
            dto.setPlateNumber(vehicle.getPlateNumber());
            dto.setVehicleType(vehicle.getVehicleType());
        }
        
        // 查询车位信息
        ParkingSpace parkingSpace = parkingSpaceMapper.selectById(reservation.getParkingSpaceId());
        if (parkingSpace != null) {
            dto.setSpaceNumber(parkingSpace.getSpaceNumber());
            dto.setParkingLotId(parkingSpace.getParkingLotId());
            
            // 查询停车场信息（如果需要）
            // ParkingLot parkingLot = parkingLotMapper.selectById(parkingSpace.getParkingLotId());
            // if (parkingLot != null) {
            //     dto.setParkingLotName(parkingLot.getName());
            // }
        }
        
        return dto;
    }

    /**
     * 获取状态描述
     *
     * @param status 状态码
     * @return 状态描述
     */
    private String getStatusDesc(Integer status) {
        if (status == null) {
            return "未知";
        }
        
        switch (status) {
            case 0:
                return "待审核";
            case 1:
                return "已确认";
            case 2:
                return "已使用";
            case 3:
                return "已取消";
            case 4:
                return "已拒绝";
            default:
                return "未知";
        }
    }

    /**
     * 计算预约费用
     *
     * @param parkingSpace 车位信息
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 预约费用
     */
    private BigDecimal calculateReservationFee(ParkingSpace parkingSpace, Date startTime, Date endTime) {
        // 获取适用的收费标准
        LambdaQueryWrapper<FeeStandard> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FeeStandard::getSpaceType, parkingSpace.getSpaceType())
                .eq(FeeStandard::getStatus, 1)  // 状态为启用的收费标准
                .le(FeeStandard::getStartTime, startTime)  // 收费标准的生效时间在预约时间范围内
                .ge(FeeStandard::getEndTime, endTime)
                .orderByDesc(FeeStandard::getCreatedAt)  // 如果有多个，取最新的
                .last("LIMIT 1");
        
        FeeStandard feeStandard = feeStandardMapper.selectOne(queryWrapper);
        if (feeStandard == null) {
            log.warn("未找到适用的收费标准，使用默认费用");
            return BigDecimal.ZERO;
        }
        
        // 计算时间差（毫秒）
        long durationMillis = endTime.getTime() - startTime.getTime();
        
        // 根据收费类型计算费用
        BigDecimal fee;
        switch (feeStandard.getFeeType()) {
            case 0: // 按小时
                long hours = (durationMillis + 3599999) / 3600000; // 向上取整小时数
                fee = feeStandard.getFeeAmount().multiply(new BigDecimal(hours));
                break;
            case 1: // 按天
                long days = (durationMillis + 86399999) / 86400000; // 向上取整天数
                fee = feeStandard.getFeeAmount().multiply(new BigDecimal(days));
                break;
            case 2: // 按月
                // 简化处理，按30天计算一个月
                long months = (durationMillis + 2591999999L) / 2592000000L; // 向上取整月数
                fee = feeStandard.getFeeAmount().multiply(new BigDecimal(months));
                break;
            case 3: // 按年
                // 简化处理，按365天计算一年
                long years = (durationMillis + 31535999999L) / 31536000000L; // 向上取整年数
                fee = feeStandard.getFeeAmount().multiply(new BigDecimal(years));
                break;
            default:
                fee = BigDecimal.ZERO;
        }
        
        // 如果设置了日封顶金额，检查是否超过
        if (feeStandard.getDayCap() != null && feeStandard.getDayCap().compareTo(BigDecimal.ZERO) > 0) {
            long totalDays = (durationMillis + 86399999) / 86400000; // 向上取整天数
            BigDecimal maxFee = feeStandard.getDayCap().multiply(new BigDecimal(totalDays));
            if (fee.compareTo(maxFee) > 0) {
                fee = maxFee;
            }
        }
        
        return fee;
    }
} 